package com.sojson.util.search.es.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.index.query.AbstractQueryBuilder;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.index.query.GeoPolygonQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;

import com.sojson.project.addr.entity.bo.Point;
import com.sojson.util.StringUtil;

/**
 * ES查询条件工具类
 * 
 * @author liu
 * @date 2022-07-25
 */
public class EsQueryBuilderUtil {

    /** 点 */
    private static final String DIAN = ".";
    /** 父类字段名 */
    private String parentFieldName;

    public EsQueryBuilderUtil() {
        this.parentFieldName = "";
    }

    public EsQueryBuilderUtil(String parentFieldName) {
        this.parentFieldName = parentFieldName + DIAN;
    }

    /**
     * 相等判断
     * 
     * @param fieldName 字段名
     * @param val       值
     * @return
     */
    public AbstractQueryBuilder<?> equals(String fieldName, Object... val) {
        return QueryBuilders.termsQuery(getFieldName(fieldName), val);
    }

    /**
     * 模糊判断
     * 
     * @param fieldName 字段名
     * @param val       值
     * @return
     */
    public AbstractQueryBuilder<?> like(String fieldName, String val) {
        return QueryBuilders.wildcardQuery(getFieldName(fieldName), StringUtil.X + val + StringUtil.X);
    }

    /**
     * in语句
     * 
     * @param fieldName 字段名
     * @param vals      值
     * @return
     */
    public AbstractQueryBuilder<?> in(String fieldName, Collection<?> vals) {
        return QueryBuilders.termsQuery(getFieldName(fieldName), vals);
    }

    /**
     * 分词比较(默认以空格分词)
     * 
     * @param fieldName 字段名
     * @param val       值
     * @return
     */
    public AbstractQueryBuilder<?> match(String fieldName, Object val) {
        return QueryBuilders.matchPhraseQuery(getFieldName(fieldName), val);
    }

    /**
     * 范围筛选
     * 
     * @param fieldName 字段名
     * @param start     开始值(包含当前值)
     * @return
     */
    public AbstractQueryBuilder<?> startEql(String fieldName, Object start) {
        RangeQueryBuilder query = QueryBuilders.rangeQuery(getFieldName(fieldName));
        if (start != null) {
            query.gte(start);
        }
        return query;
    }

    /**
     * 范围筛选
     * 
     * @param fieldName 字段名
     * @param end       结束值(不包含当前值)
     * @return
     */
    public AbstractQueryBuilder<?> endEql(String fieldName, Object end) {
        RangeQueryBuilder query = QueryBuilders.rangeQuery(getFieldName(fieldName));
        if (end != null) {
            query.lt(end);
        }
        return query;
    }

    /**
     * 区间筛选
     * 
     * @param fieldName 字段名
     * @param start     开始值(包含当前值)
     * @param end       结束值(包含当前值)
     * @return
     */
    public AbstractQueryBuilder<?> between(String fieldName, Object start, Object end) {
        RangeQueryBuilder query = QueryBuilders.rangeQuery(getFieldName(fieldName));
        if (start != null) {
            query.gte(start);
        }
        if (end != null) {
            query.lte(end);
        }
        return query;
    }

    /**
     * 根据地图距离筛选
     * 
     * @param fieldName 字段名
     * @param point     经纬度
     * @return
     */
    public AbstractQueryBuilder<?> distance(String fieldName, Point point, Integer dist) {
        Double lon = point.getLon();
        Double lat = point.getLat();
        if (lon == null || lat == null) {
            return null;
        }

        GeoDistanceQueryBuilder query = QueryBuilders.geoDistanceQuery(getFieldName(fieldName));
        return query.distance(dist + "").point(lat, lon);
    }

    /**
     * 根据地图范围筛选
     * 
     * @param fieldName 字段名
     * @param points    经纬度集合
     * @return
     */
    public AbstractQueryBuilder<?> between(String fieldName, List<Point> points) {
        if (points == null || points.size() < 1) {
            return null;
        }

        List<GeoPoint> geoPoints = new ArrayList<>();
        for (Point point : points) {
            Double lon = point.getLon();
            Double lat = point.getLat();
            if (lon == null || lat == null) {
                continue;
            }

            geoPoints.add(new GeoPoint(lat.doubleValue(), lon));
        }
        if (geoPoints.size() < 1) {
            return null;
        }

        return new GeoPolygonQueryBuilder(getFieldName(fieldName), geoPoints);
    }

    /**
     * 获取字段名
     * 
     * @param fieldName
     * @return
     */
    public String getFieldName(String fieldName) {
        return parentFieldName + fieldName;
    }

}